package br.org.bertol.mestrado;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.CountDownLatch;

import br.org.bertol.mestrado.engine.EnginePso;
import br.org.bertol.mestrado.engine.Objective;
import br.org.bertol.mestrado.engine.optimisation.pso.TypeMovement;
import br.org.bertol.mestrado.util.Configurator;

/**
 * @author contaqualquer
 */
public class StarterPSO extends AbstractStarter<EnginePso> {

    public StarterPSO(Configurator configurator) {
        super(configurator);
    }

    /**
     * 
     */
    @Override
    public void startEngine() throws InterruptedException {
        startPsoEngineBySystem(configurator.getIteracoes(), configurator
                .getSourcePath());
    }

    /**
     * @param avaliacoes
     * @param sourePath
     * @throws InterruptedException
     */
    public final void startPsoEngineBySystem(final int avaliacoes,
            final String sourePath) throws InterruptedException {
        for (String system : configurator.getSystems()) {
            startPsoEngineByInput(avaliacoes, sourePath, system);
        }
    }

    /**
     * @param avaliacoes
     * @param sourePath
     * @param system
     * @throws InterruptedException
     */
    public void startPsoEngineByInput(final int avaliacoes,
            final String sourePath, final String system)
            throws InterruptedException {
        for (Objective[] objectives : configurator.getObjectives()) {
            startPsoEngineByMovement(objectives, avaliacoes, sourePath, system);
        }
    }

    /**
     * @param constraint
     * @param avaliacoes
     * @param sourePath
     * @param system
     * @throws InterruptedException
     */
    public void startPsoEngineByMovement(final Objective[] constraint,
            final int avaliacoes,
            final String sourePath, final String system)
            throws InterruptedException {
        // colocar aqui carga de entrada de movimentos
        for (TypeMovement movement : configurator.getTypeMovements()) {
            startPsoEngine(movement, constraint, avaliacoes, sourePath, system);
        }
    }

    /**
     * @param typeMovement
     * @param constraint
     * @param avaliacoes
     * @param sourePath
     * @param system
     * @throws InterruptedException
     *             Caso ocorra algum erro ao sincronizar as threads
     */
    public void startPsoEngine(final TypeMovement typeMovement,
            final Objective[] constraint, final int avaliacoes,
            final String sourePath, final String system)
            throws InterruptedException {

        final CountDownLatch systemstart = new CountDownLatch(1);

        final CountDownLatch systemstop = new CountDownLatch(1);

        // inicia pso
        final EnginePso enginePso = new EnginePso(systemstart, systemstop,
                avaliacoes,
                constraint, sourePath, system, typeMovement, configurator
                .getInitialInertia(),
                configurator.getFinalInertia(), configurator
                .getCognitivoFactor(),
                configurator.getSocialFactor(), configurator.getDepth(),
                configurator.getRepositorySize(), configurator
                .getPopulationSize());

        enginePso.start();

        // notifica threads que
        // buscas podem iniciar
        systemstart.countDown();

        // coloca sistema em modo de espera
        // pela conclus�o das buscas
        systemstop.await();

        // adiciona na lista de solu��es
        engineList.add(enginePso);
    }

    /**
     * @throws IOException
     *             Caso tenha erro ao manipular o arquivo
     */
    @Override
    public final void save() throws IOException {

        final String fileName = configurator.getSourcePath() + "/"
                + configurator.getOutPutFile();

        final PrintWriter outFile = new PrintWriter(new BufferedWriter(
                new FileWriter(fileName, true)));

        outFile.println("RESULTADO ParticleSwarmOptimization");

        for (EnginePso enginePso : engineList) {
            enginePso.writeToFile(outFile);
        }

        outFile.close();
    }
}
